package il.ac.biu.cs.grossmm.api.keys;

import java.util.NoSuchElementException;

/**
 * Represents active data key. Active data keys are used to identify virtual
 * resources such as "presence information as pulished by a mobile phone of
 * Alice", an "aggregated presence information", "a watcher information of
 * Alice", and so on.
 * <p>
 * Logical structure of data key is a recursive data structure where a key is
 * associated with a value and with a set (possibly empty) of subkeys where each
 * subkey has a unique attribute within a key.
 */
public interface Key {
	/**
	 * The null key: a key with a null value and no entries
	 */
	Key NULL = new Key() {
		public KeyEntry entry(int i)
		{
			throw new NoSuchElementException();
		}

		public Key subkey(Attribute a)
		{
			return null;
		}

		public Object value()
		{
			return null;
		}

		public Object value(Attribute a)
		{
			return null;
		}

		public int size()
		{
			return 0;
		}

		@Override
		public int hashCode()
		{
			return 0;
		}

		@Override
		public boolean equals(Object obj)
		{
			if (obj == NULL)
				return true; // optimization

			if (!(obj instanceof Key))
				return false;

			Key key = (Key) obj;
			return key.value() == null && key.size() == 0;
		}

	};

	Object value();

	/**
	 * Equivalent to <tt>subkey(a).value</tt> except that if
	 * <tt>subkey(a) == null</tt> a <tt>null</tt> is returned, no exception
	 * is thrown
	 * 
	 * @param a
	 *            attribute
	 * @return a value of the subkey associated with this attribute
	 */
	Object value(Attribute a);

	/**
	 * Gets number of subkeys in this key
	 * @return number of subkeys in this key
	 */
	int size();

	/**
	 * Gets an i-th key entry in this key. A key entry is an attribute-key pair.
	 * @param i index
	 * @return i-th key entry in this key
	 */
	KeyEntry entry(int i);

	/**
	 * Gets a subkey of this key by its attribute
	 * @param a an attribute of a subkey to get
	 * @return the subkey
	 */
	Key subkey(Attribute a);
}
